#include "iotgo_mySocketServer_interface.h"
#include "iotgo_debug.h"


#define debugPrint socketServerDebugPrint

#define MAX_DOMAIN_LEN 20

/*macro: socket state*/
#define SERVER_NOT_INITED         0
#define SERVER_OBJ_IS_INITED      1
#define SERVER_LISTEN_IS_READY    2
#define SERVER_ACCEPT_A_CLIENT    3

struct mySocketServer_interface
{
    int32_t socket_fd;
    int32_t con_fd;
    int32_t listen_port;
    volatile int8_t  state;
    struct sockaddr_in server_address;
    struct sockaddr_in client_address;
    fd_set readfds;
};


MySocketServer *setupSocketServer(uint32_t listen_port)
{
    MySocketServer *p_socket = NULL;
    int32_t server_len;

    p_socket = (MySocketServer *) pMalloc(sizeof(MySocketServer));

    if(!p_socket)
    {
	return NULL;
    }

    memset(p_socket,0,sizeof(MySocketServer));
    p_socket->state = SERVER_OBJ_IS_INITED;
    p_socket->listen_port = listen_port;
    return p_socket;
} 

int8_t cleanSocketServer(MySocketServer **pp_mysocket)
{
	MySocketServer *p_mysocket = NULL;
	p_mysocket = *pp_mysocket;
    debugPrint("[%s]cleanSocketServer start\n",__FUNCTION__);
    if(!p_mysocket)
    {
		debugPrint("[%s]cleanSocketServer done\n",__FUNCTION__);
		return MYSOCKETSERVER_SUCCESS;
    }

    switch(p_mysocket->state)
    {
    case SERVER_ACCEPT_A_CLIENT:
        debugPrint("[%s]close the connection fd\n",__FUNCTION__);
        close(p_mysocket->con_fd);
        p_mysocket->state--; 
    case SERVER_LISTEN_IS_READY:
        debugPrint("[%s]close the socket fd\n",__FUNCTION__);
        close(p_mysocket->socket_fd);
        p_mysocket->state--; 
    case SERVER_OBJ_IS_INITED:
        if(p_mysocket)
        {
            debugPrint("[%s]free MySocketServer object\n",__FUNCTION__);
			p_mysocket->state--;
            pFree(p_mysocket);
			p_mysocket = NULL;
			debugPrint("[%s]cleanSocketServer done\n",__FUNCTION__);
            return MYSOCKETSERVER_SUCCESS;
        }   
	break;
    case SERVER_NOT_INITED:
	debugPrint("[%s]cleanSocketServer done\n",__FUNCTION__);
	return MYSOCKETSERVER_SUCCESS;
    default:
	break;
    }
    return MYSOCKETSERVER_FAIL;
}


int8_t waitForClient(MySocketServer *p_mysocket)
{
    int32_t client_len;
    int32_t server_len;
    int32_t ret;

    struct timeval timeout;
    timeout.tv_sec = 10000;
    timeout.tv_usec = 0;
    printf("[%s]p_mysocket->state is %d\n",__FUNCTION__,p_mysocket->state);
    switch(p_mysocket->state)
    {
    case SERVER_OBJ_IS_INITED:
	p_mysocket->socket_fd = socket(AF_INET,SOCK_STREAM,0);

	p_mysocket->server_address.sin_family = AF_INET;
	p_mysocket->server_address.sin_addr.s_addr = htonl(INADDR_ANY);
	p_mysocket->server_address.sin_port = htons(p_mysocket->listen_port);
	server_len = sizeof(p_mysocket->server_address);

	ret = bind(p_mysocket->socket_fd, (struct sockaddr * ) &(p_mysocket->server_address), server_len);
	ret = listen(p_mysocket->socket_fd, 5);
	debugPrint("[%s]servier is listenning\n",__FUNCTION__);
	FD_ZERO(&(p_mysocket->readfds));
	FD_SET(p_mysocket->socket_fd,&(p_mysocket->readfds));
	p_mysocket->state = SERVER_LISTEN_IS_READY;
	//break;
    case SERVER_LISTEN_IS_READY:
	debugPrint("[%s]before select socket_fd is %d\n",__FUNCTION__,p_mysocket->socket_fd);
	ret = select(FD_SETSIZE, &(p_mysocket->readfds),NULL,NULL,&timeout);
	if(ret < 0)
	{
	    cleanSocketServer(&p_mysocket);
	}
	else if (ret == 0)
	{
	    //debugPrint("select ret 0\n");
	}
	else
	{
	    debugPrint("[%s]select ret is %d\n",__FUNCTION__,ret);
	    if(FD_ISSET(p_mysocket->socket_fd,&(p_mysocket->readfds)))
	    {
		debugPrint("[%s]here accept a client\n",__FUNCTION__);
		debugPrint("[%s]socket_fd is %d\n",__FUNCTION__,p_mysocket->socket_fd);
		client_len = sizeof(p_mysocket->client_address);
		p_mysocket->con_fd = accept(p_mysocket->socket_fd,
					    (struct sockaddr *) &(p_mysocket->client_address),
					    &client_len);
		if(p_mysocket->con_fd >= 0)
		{
		    FD_SET(p_mysocket->con_fd,&(p_mysocket->readfds));
		    p_mysocket->state = SERVER_ACCEPT_A_CLIENT;
		    debugPrint("[%s]accept a client\n",__FUNCTION__);
		}
		else
		{
		    /*this is for close() to complete. Need to be rewrotten.*/
		    systemDelayMs(100);
		}
	    }
	}
	break;
    case SERVER_ACCEPT_A_CLIENT:
	return MYSOCKETSERVER_SUCCESS;
    case SERVER_NOT_INITED:
    default:
	break;
    }
    return MYSOCKETSERVER_FAIL;
}

int32_t readFromClient(MySocketServer *p_mysocket,uint8_t *buf, uint32_t len)
{
    int32_t ret = 1;

    ret = recv(p_mysocket->con_fd,buf,len,0);
    if(ret > 0)
    {
        return ret;
    }
    return MYSOCKETSERVER_FAIL;
}

int32_t readFromClientNonBlock(MySocketServer *p_mysocket,uint8_t *buf, uint32_t len)
{
    return 0;
}

int32_t writeToClient(MySocketServer *p_mysocket,uint8_t *buf, uint32_t len)
{
    int32_t ret;
    ret = send(p_mysocket->con_fd,buf,len,0);
    if(ret >= 0)
    {
        return ret;
    }
    return MYSOCKETSERVER_FAIL;
}

int32_t closeCurrentClient(MySocketServer *p_mysocket)
{
    if(p_mysocket->state == SERVER_ACCEPT_A_CLIENT)
    {
        FD_CLR(p_mysocket->con_fd,&(p_mysocket->readfds));
        close(p_mysocket->con_fd);
        p_mysocket->state = SERVER_LISTEN_IS_READY;
    }
    return 0;
}


